package com.iussoft.receiveData.redis;

import com.apache.tools.DateUtils;
import com.apache.tools.StrUtil;
import com.iussoft.es.ElasticOperationService;
import com.iussoft.es.config.EsClientFactory;
import com.iussoft.es.entity.Field;
import com.iussoft.tools.LoggerUtil;
import com.netflix.appinfo.InstanceInfo;
import com.netflix.discovery.DiscoveryManager;
import com.netflix.discovery.shared.Application;
import io.searchbox.client.JestClient;
import io.searchbox.core.Bulk;
import io.searchbox.core.DocumentResult;
import io.searchbox.core.Index;
import net.sf.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.*;

/**
 * @description: ES操作接口实现
 * @author: Hou Dayu
 * @date: Created in 2020/2/24
 */
@Component
public class EsManager {

    @Autowired
    private ElasticOperationService elasticOperationService;

    public boolean saveInfoForLogs(String indexName,String aliases,String id,Map<String,String> data){
        if(!elasticOperationService.indexExists(indexName)){
            JSONObject json = null;
            if(StrUtil.isNotNull(aliases)){
                json = JSONObject.fromObject("{\"aliases\": \""+aliases+"\",\"numbershards\":3}");
            }
            elasticOperationService.createIndex(indexName, "doc", json, logsMapping());
        }
        data.put("indexDate", DateUtils.format(new Date(),"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"));
        return createIndexInfo(indexName,"doc", id, data);
    }

    public boolean saveInfoForEs(String indexName,String aliases,String id,JSONObject info){
        if(!elasticOperationService.indexExists(indexName)){
            JSONObject json = null;
            if(StrUtil.isNotNull(aliases)){
                json = JSONObject.fromObject("{\"aliases\": \""+aliases+"\",\"numbershards\":5}");
            }
            elasticOperationService.createIndex(indexName, "doc", json, getIndexMapping(indexName));
        }
        return elasticOperationService.createIndexInfo(indexName,"doc",id,info);
    }

    public boolean saveInfoForEs(String indexName,String aliases,String id,Map<String,Object> info){
        if(!elasticOperationService.indexExists(indexName)){
            JSONObject json = null;
            if(StrUtil.isNotNull(aliases)){
                json = JSONObject.fromObject("{\"aliases\": \""+aliases+"\",\"numbershards\":5}");
            }
            elasticOperationService.createIndex(indexName, "doc", json, getIndexMapping(indexName));
        }
        return createIndexInfo(indexName,"doc",id,info);
    }

    /**
     * 批量插入ES
     * @param indexName 索引名
     * @param aliases   别名可空
     * @param indexType 信息类型(log,doc)
     * @param infos
     * @return
     */
    public boolean batchSaveInfos(String indexName,String aliases,String indexType,List<Map<String,Object>> infos){
        if(!elasticOperationService.indexExists(indexName)){
            JSONObject json = null;
            if(StrUtil.isNotNull(aliases)){
                json = JSONObject.fromObject("{\"aliases\": \""+aliases+"\",\"numbershards\":5}");
            }
            elasticOperationService.createIndex(indexName, "doc", json, "log".equalsIgnoreCase(indexType) ? logsMapping() : getIndexMapping(indexName));
        }
        if(StrUtil.isEmpty(infos)){
            return false;
        }
        int count = infos.size();
        try {
            List<Index> monitorList = new ArrayList();
            for(int i=0; i<count; i++){
                Map<String,Object> info = infos.get(i);
                String id = StrUtil.doNull(String.valueOf(info.get("rowkey")),"");
                monitorList.add(new Index.Builder(info).id(id).build());
            }
            Bulk bulk = new Bulk.Builder().defaultIndex(indexName).defaultType("doc")
                    .addAction(monitorList).build();
            EsClientFactory.defClient().execute(bulk);
            monitorList = null;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    public boolean delDocByQuery(String indexName, List<Field> fields){
        return elasticOperationService.delDocByQuery(indexName,fields);
    }

    private boolean createIndexInfo(String indexName, String type, String docId, Map data) {
        boolean isDeleteSuccess = true;
        try {
            Index.Builder indexBuilder=new Index.Builder(data);
            indexBuilder.index(indexName).type(type).id(docId);
            Index index = indexBuilder.build();

            JestClient jsClient = EsClientFactory.defClient();
            DocumentResult result = jsClient.execute(index);

            if (result==null || !result.isSucceeded()) {
                isDeleteSuccess =false;
            }
            LoggerUtil.infoSource("create index info result {}",result.getJsonString());
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
        return isDeleteSuccess;
    }

    private JSONObject getIndexMapping(String indexName){
        if(indexName.startsWith("depositcertificate")) {
            StringBuilder sb = new StringBuilder();
            sb.append("{\"doc\":{\"properties\":{");
            sb.append("\"infoId\":{\"type\":\"keyword\"}");
            sb.append(",\"traceId\":{\"type\":\"keyword\"}");
            sb.append(",\"rowkey\":{\"type\":\"keyword\"}");
            sb.append(",\"sourceCode\":{\"type\":\"keyword\"}");
            sb.append(",\"interfaceCode\":{\"type\":\"keyword\"}");
            sb.append(",\"infterfacePwd\":{\"type\":\"keyword\"}");
            sb.append(",\"flag\":{\"type\":\"keyword\"}");
            sb.append(",\"createdTime\":{\"type\":\"date\"}");
            sb.append(",\"tableName\":{\"type\":\"keyword\"}");
            sb.append(",\"message\":{\"type\":\"text\"}");
            sb.append("}}}");
            JSONObject json = JSONObject.fromObject(sb.toString());
            return json;
        } else if(indexName.startsWith("dataanalyze")) {
            StringBuilder sb = new StringBuilder();
            sb.append("{\"doc\":{\"properties\":{");
            sb.append("\"rowkey\":{\"type\":\"keyword\"}");
            sb.append(",\"traceId\":{\"type\":\"keyword\"}");
            sb.append(",\"sourceCode\":{\"type\":\"keyword\"}");
            sb.append(",\"interfaceCode\":{\"type\":\"keyword\"}");
            sb.append(",\"infoType\":{\"type\":\"keyword\"}");
            sb.append(",\"createdTime\":{\"type\":\"date\"}");
            sb.append(",\"tableName\":{\"type\":\"keyword\"}");
            sb.append(",\"message\":{\"type\":\"text\"}");
            sb.append("}}}");
            JSONObject json = JSONObject.fromObject(sb.toString());
            return json;
        } else {
            StringBuilder sb = new StringBuilder();
            sb.append("{\"doc\":{\"properties\":{");
            sb.append("\"traceId\":{\"type\":\"keyword\"}");
            sb.append(",\"@timestamp\":{\"type\":\"date\"}");
            sb.append("}}}");
            JSONObject json = JSONObject.fromObject(sb.toString());
            return json;
        }
    }

    /**
     * 日志索引Mapping
     */
    private JSONObject logsMapping(){
        StringBuilder sb = new StringBuilder();
        sb.append("{\"doc\" : {\"properties\" : {");
        sb.append("\"ipAddress\" : {\"type\" : \"keyword\"},");
        sb.append("\"traceId\" : {\"type\" : \"keyword\"},");
        sb.append("\"exeSys\" : {\"type\" : \"keyword\"},");
        sb.append("\"requestUrl\" : {\"type\" : \"keyword\"},");
        sb.append("\"requestTime\" : {\"type\" : \"keyword\"},");
        sb.append("\"infoType\" : {\"type\" : \"keyword\"},");
        sb.append("\"interfaceCode\" : {\"type\" : \"keyword\"},");
        sb.append("\"requestIp\" : {\"type\" : \"keyword\"},");
        sb.append("\"processingStage\" : {\"type\" : \"keyword\"},");
        sb.append("\"type\" : {\"type\" : \"keyword\"},");
        sb.append("\"rowkey\" : {\"type\" : \"keyword\"},");
        sb.append("\"requestCode\" : {\"type\" : \"keyword\"},");
        sb.append("\"processingResult\" : {\"type\" : \"keyword\"},");
        sb.append("\"exception\" : {\"type\" : \"keyword\"},");
        sb.append("\"indexDate\": {\"type\": \"date\"},");
        sb.append("\"level\" : {\"type\" : \"keyword\"}");
        sb.append(",\"responseBody\" : {\"type\" : \"text\"},");
        sb.append("\"requestBody\" : {\"type\" : \"text\"},");
        sb.append("\"message\" : {\"type\" : \"text\"}");
        sb.append("}}}");
        JSONObject json = JSONObject.fromObject(sb.toString());
        return json;
    }

    public String getRequestUrl(String serviceId){
        serviceId = StrUtil.doNull(serviceId,"data-write-server");
        DiscoveryManager discoveryClient = DiscoveryManager.getInstance();
        Application app = discoveryClient.getEurekaClient().getApplication(serviceId.toUpperCase());
        if(app != null) {
            int dszie = app.getInstances().size();
            if (dszie > 0) {
                InstanceInfo instances = null;
                if(dszie > 1) {
                    Random rand = new Random();
                    instances = app.getInstances().get(rand.nextInt(dszie));
                } else {
                    instances = app.getInstances().get(0);
                }
                return instances.getHomePageUrl();
            }
        }
        return "";
    }
}
